#include "b2ObjectFactory.h"


b2ObjectFactory::b2ObjectFactory(b2World* w, b2UserDataManager* udm) {
	userDataManager = udm;
	world = w;
	running = false;
}
b2ObjectFactory::~b2ObjectFactory() {

}

void b2ObjectFactory::reset() {
	post("resetting");
	running = false;
	initShapeDefs();
	
	

}



void b2ObjectFactory::begin(long ac, t_atom * av) {
	post("begin object!!");
	running = true;
	
	/* make sure there's an object type AND and name */
	if(ac < 2) {
		error("need an object type and a name");
		reset();
		return;
	}
	
	/* get the object type and name */
	char* objtype = (atom_getsym(av))->s_name;
	char* objname = (atom_getsym(av+1))->s_name;

	/* make sure name is unique */
	if(userDataManager->has(objname)) {
		error("an object named \"%s\" already exists.",objname);
		reset();
		return;
	} else {
		objectName = objname;
	}	
	
	ac-=2; // skip forward two elements
	av+=2; // skip forward two elements


	/* reset all shape defs to default */
	initShapeDefs();
		
	if(EQUALS(objtype,"body")) {
		beginBody(ac,av);
	} else if (EQUALS(objtype,"circle")) {
		beginCircle(ac,av);
	} else if (EQUALS(objtype,"polygon")) {
		beginPolygon(ac,av);
	} else if (EQUALS(objtype,"box")) {
		beginBox(ac,av);
	} else if (EQUALS(objtype,"revolutejoint")) {
		beginRevoluteJoint(ac,av);
	} else if (EQUALS(objtype,"distancejoint")) {
		beginDistanceJoint(ac,av);
	} else if (EQUALS(objtype,"prismaticjoint")) {
		beginPrismaticJoint(ac,av);
	} else if (EQUALS(objtype,"pulleyjoint")) {
		beginPullyJoint(ac,av);
	} else if (EQUALS(objtype,"gearjoint")) {
		beginGearJoint(ac,av);
	} else if (EQUALS(objtype,"mousejoint")) {
		beginMouseJoint(ac,av);
	} else {
		error("unknown object type");
		reset();
		return;
	}

}



void b2ObjectFactory::end(long ac, t_atom * av) {

	switch (currentObjectType) {
		/* bodies */
		case e_b2BodyType:
			endBody();
			break;
		/* shapes */
		case e_b2CircleShapeType:
			endCircle();
			break;
		case e_b2PolygonShapeType:
			endPolygon();
			break;
		/* joints */	
		case e_b2DistanceJointType:
			endDistanceJoint();
			break;		
		case e_b2GearJointType:
			endGearJoint();
			break;	
		case e_b2MouseJointType:
			endMouseJoint();
			break;	
		case e_b2PrismaticJointType:
			endPrismaticJoint();
			break;	
		case e_b2PulleyJointType:
			endPullyJoint();
			break;
		case e_b2RevoluteJointType:
			endRevoluteJoint();
			break;
		default:
			//error("couldn't assign user data to object");
			break;
	}


//	post("end object!");
	running = false;
	reset(); 

}


void b2ObjectFactory::initShapeDefs() {

		drawMe = true;
		
		userDataCount = 0;
		//userDataValue = NULL; // no dork.

		/* reuseable body definitions */
		bodyDef = b2BodyDef();

		/* reuseable shape definitions */
		circleShapeDef = b2CircleDef();
		polyShapeDef = b2PolygonDef();
		// clear the poly points
		vertices.clear();
				
		/* reuseable joint definitions */
		distanceJointDef = b2DistanceJointDef();
		gearJointDef = b2GearJointDef();
		mouseJointDef = b2MouseJointDef();
		prismaticJointDef = b2PrismaticJointDef();
		pulleyJointDef = b2PulleyJointDef();
		revoluteJointDef = b2RevoluteJointDef();



}


void b2ObjectFactory::anything(t_symbol * s, long ac, t_atom * av) {

			
		if(EQUALS(s->s_name,"userdata") && ac >= 0) {
			// copy it over
			
			userDataCount = 0;
			if(ac > 0) {		
				for(int i = 0; i < ac; i++) {
					userDataCount++;
					userDataValue[i] = av[i];
				}
			} 
			return;
		}



	
		if(EQUALS(s->s_name,"reset")) {
			reset();
		
		} else if(EQUALS(s->s_name,"begin")) {
			/* this is where things begin */
			
			/* are we currently creating an object? */
			if(running) {
				error("You cannot create a new object until you finish the last object.");
			} else {
				begin(ac,av);
			}
			
		} else if(EQUALS(s->s_name,"end")) {
			if(running) {
				end(ac,av);
			} else {
				error("You cannont end an object until you start one.");
			}
			
		} else if(EQUALS(s->s_name,"destroy")) {	
			destroy(ac,av);
		/* intercept some special parameters */			
			

		} else if(EQUALS(s->s_name,"drawme")) {
			error("drawme not yet implemeted");
	
		/* process all the rest of the parameters */
		} else {
			if(running) {
			
					setParam(s,ac,av);
			
			
			} else {
				error("You cannot set a parameter without starting an object");
			}
		}
		
	
				

}

void b2ObjectFactory::destroy(long ac, t_atom * av) {

	b2UserData* ud;
	b2Body* body;
	
	if(ac != 1) {
		error("need something to destroy");
		return;
	}

	char* name = atom_getsym(av)->s_name;
	
	if(userDataManager->has(name)) {
		ud = userDataManager->get(name);
	} else {
		error("no object called \"%s\" to destroy",name);
		return;
	}


	switch (ud->b2ObjectType) {
		/* bodies */
		case e_b2BodyType:
			body = (b2Body*)ud->b2Object;
			world->DestroyBody(body);
			// remove from hash
			userDataManager->remove(ud->name);

			//!! THE LISTENERS IS CALLED TO RID THE USER HASH OF THE SHAP E AND JOINT REFS

			break;
		/* shapes */
		case e_b2CircleShapeType:
		
			b2CircleShape* cs = (b2CircleShape*)ud->b2Object;
			body = cs->GetBody();
			body->DestroyShape(cs);
			body->SetMassFromShapes();
			body->WakeUp();
			
			// remove from hash
			userDataManager->remove(ud->name);

			break;
		case e_b2PolygonShapeType:
			
			/* GO THROUGH ALL IN GROUP AND DESTROY */
			
//			b2PolygonShape* ps = *ud->polys; // get a pointer to that inside array
			int nPolys = ud->nPolys;
			
			for(int i = 0; i < nPolys; i++) {
				body = ud->polys[i]->GetBody();
				body->DestroyShape(ud->polys[i]);
				body->SetMassFromShapes();
				body->WakeUp();
			}
			
			// remove from hash
			userDataManager->remove(ud->name);

			break;
		/* joints */	
		case e_b2DistanceJointType:
			world->DestroyJoint((b2DistanceJoint*)ud->b2Object);
			// wake up bodies?
			// remove from hash
			userDataManager->remove(ud->name);

			break;		
		case e_b2GearJointType:
			world->DestroyJoint((b2GearJoint*)ud->b2Object);
			// wake up bodies?
			// remove from hash
			userDataManager->remove(ud->name);

			break;	
		case e_b2MouseJointType:
			world->DestroyJoint((b2MouseJoint*)ud->b2Object);
			// wake up bodies?
			// remove from hash
			userDataManager->remove(ud->name);

			break;	
		case e_b2PrismaticJointType:
			world->DestroyJoint((b2PrismaticJoint*)ud->b2Object);
			// wake up bodies?
			// remove from hash
			userDataManager->remove(ud->name);

			break;	
		case e_b2PulleyJointType:
			world->DestroyJoint((b2DistanceJoint*)ud->b2Object);
			// wake up bodies?
			// remove from hash
			userDataManager->remove(ud->name);

			break;
		case e_b2RevoluteJointType:
			world->DestroyJoint((b2RevoluteJoint*)ud->b2Object);
			// wake up bodies?
			// remove from hash
			userDataManager->remove(ud->name);

			break;
		default:
			//error("couldn't assign user data to object");
			break;
	}



}

void b2ObjectFactory::setParam(t_symbol * s, long ac, t_atom * av) {

	switch (currentObjectType) {
		/* bodies */
		case e_b2BodyType:
			setParameter(s->s_name,bodyDef,ac,av);
			break;
		/* shapes */
		case e_b2CircleShapeType:
			setParameter(s->s_name,circleShapeDef,ac,av);
			break;
		case e_b2PolygonShapeType:
			setParameter(s->s_name,polyShapeDef,ac,av,&vertices); // custom vertices vector!
			break;
		/* joints */	
		case e_b2DistanceJointType:
			setParameter(s->s_name,distanceJointDef,ac,av);
			break;		
		case e_b2GearJointType:
			setParameter(s->s_name,gearJointDef,ac,av);
			break;	
		case e_b2MouseJointType:
			setParameter(s->s_name,mouseJointDef,ac,av);
			break;	
		case e_b2PrismaticJointType:
			setParameter(s->s_name,prismaticJointDef,ac,av);
			break;	
		case e_b2PulleyJointType:
			setParameter(s->s_name,pulleyJointDef,ac,av);
			break;
		case e_b2RevoluteJointType:
			setParameter(s->s_name,revoluteJointDef,ac,av);
			break;
		default:
			//error("couldn't assign user data to object");
			break;
	}

}

void b2ObjectFactory::beginBody(long ac, t_atom * av) {
	//xxxbeginxx(was deleted) xxxbodyxxxx BODY_NAME
	if(ac == 2) {
		currentObjectType = e_b2BodyType;		
		bodyDef.position = b2Vec2(P2M(atom_getfloat(av)),P2M(atom_getfloat(av+1)));


	} else {
		error("body needs NAME START_X START_Y");
		reset();
		return;
	}



}

void b2ObjectFactory::beginCircle(long ac, t_atom * av) {
	//begin circle SHAPE_NAME PARENT_BODY
	if(ac == 1) {
		currentObjectType = e_b2CircleShapeType;
		
		char* parentBodyName =  (atom_getsym(av))->s_name;
		
		if(userDataManager->has(parentBodyName)) {
			body1 = userDataManager->getBody(parentBodyName);
			parentBody1 = parentBodyName;
		} else {
			error("no such parent body \"%s\" exists.",parentBodyName);
			reset();
			return;
		}

	
	} else {
		error("begin circle SHAPE_NAME PARENT_BODY");
		reset();
		return;
	}


}

void b2ObjectFactory::beginPolygon(long ac, t_atom * av) {
	//begin polygon SHAPE_NAME PARENT_BODY
	if(ac == 1) {
		currentObjectType = e_b2PolygonShapeType;

		char* parentBodyName =  (atom_getsym(av))->s_name;
		
		if(userDataManager->has(parentBodyName)) {
			body1 = userDataManager->getBody(parentBodyName);
			parentBody1 = parentBodyName;
		} else {
			error("no such parent body \"%s\" exists.",parentBodyName);
			reset();
			return;
		}



	} else {
		error("begin polygon SHAPE_NAME PARENT_BODY");
		reset();
		return;
	}
}

void b2ObjectFactory::beginBox(long ac, t_atom * av) {
//begin box SHAPE_NAME PARENT_BODY half_width half_height
	if(ac >= 3) {
		currentObjectType = e_b2PolygonShapeType;		

		char* parentBodyName =  (atom_getsym(av))->s_name;
		
		if(userDataManager->has(parentBodyName)) {
			body1 = userDataManager->getBody(parentBodyName);
			parentBody1 = parentBodyName;
		} else {
			error("no such parent body \"%s\" exists.",parentBodyName);
			reset();
			return;
		}

		if(ac == 3) { // parent, half-w, halfh, etc
			polyShapeDef.SetAsBox(P2M(atom_getfloat(av+1)),		// half height
								  P2M(atom_getfloat(av+2)));	// half width
								  
			// put poly vertices into our custom vector
			for(int i = 0; i < polyShapeDef.vertexCount; i++) {
				vertices.push_back(polyShapeDef.vertices[i]);
			}
		
							  
											  				  
								  
		} else if(ac == 6) { // parent, etc .
			polyShapeDef.SetAsBox(P2M(atom_getfloat(av+1)),	// half height
								  P2M(atom_getfloat(av+2)),	// half width
								  b2Vec2(P2M(atom_getfloat(av+3)),P2M(atom_getfloat(av+4))), // local center x, y
								  atom_getfloat(av+5)); // local rotation

			// put poly vertices into our custom vector
			for(int i = 0; i < polyShapeDef.vertexCount; i++) {
				vertices.push_back(polyShapeDef.vertices[i]);
			}

		} else {
			error("begin box SHAPE_NAME PARENT_BODY half_width half_height or begin box SHAPE_NAME PARENT_BODY half_width half_height local_center_x local_center_y local_angle");
			reset();
			return;
		} 
	} else {
			error("begin box SHAPE_NAME PARENT_BODY half_width half_height or begin box SHAPE_NAME PARENT_BODY half_width half_height local_center_x local_center_y local_angle");
		reset();
		return;
	}
}

void b2ObjectFactory::beginRevoluteJoint(long ac, t_atom * av) {
//begin revolutejoint JOINT_NAME BODY_1_NAME BODY_2_NAME anchor_x anchor_y
	if(ac == 4) {
			currentObjectType = e_b2RevoluteJointType;		
			
			char* body1Name =  (atom_getsym(av))->s_name;
			char* body2Name =  (atom_getsym(av+1))->s_name;
		
			if(userDataManager->has(body1Name)) {
				body1 = userDataManager->getBody(body1Name);
				parentBody1 = body1Name;
			} else {
				error("no such parent body \"%s\" exists.",body1Name);
				reset();
				return;
			}

			if(userDataManager->has(body2Name)) {
				body2 = userDataManager->getBody(body2Name);
				parentBody2 = body2Name;
			} else {
				error("no such parent body \"%s\" exists.",body2Name);
				reset();
				return;
			}
			
			
			b2Vec2 anchor(P2M(atom_getfloat(av+2)),P2M(atom_getfloat(av+3)));
			
			revoluteJointDef.Initialize(body1,body2,anchor);
			
			
	
	} else {
		error("begin revolutejoint JOINT_NAME BODY_1_NAME BODY_2_NAME anchor_x anchor_y");
		reset();
		return;
	}


}

void b2ObjectFactory::beginDistanceJoint(long ac, t_atom * av) {
//begin distancejoint JOINT_NAME BODY1_NAME BODY2_NAME worldAnchor1_x worldAnchor1_y worldAnchor2_x worldAnchor2_y
	if(ac == 6) {
			currentObjectType = e_b2DistanceJointType;
			
			error("distance joint is not finished yet");
			reset();
			return;

	} else {
		error("begin distancejoint JOINT_NAME BODY1_NAME BODY2_NAME worldAnchor1_x worldAnchor1_y worldAnchor2_x worldAnchor2_y");
		reset();
		return;
	}
}

void b2ObjectFactory::beginPrismaticJoint(long ac, t_atom * av) {
//begin prismaticjoint JOINT_NAME BODY1_NAME BODY2_NAME anchor_x anchor_y axis_x axis_y
	if(ac == 6) {
			currentObjectType = e_b2PrismaticJointType;		
			error("prismatic joint is not finished yet");
			reset();
			return;

	
	} else {
		error("begin prismaticjoint JOINT_NAME BODY1_NAME BODY2_NAME anchor_x anchor_y axis_x axis_y");
		reset();
		return;
	}
}

void b2ObjectFactory::beginPullyJoint(long ac, t_atom * av) {
//begin pulleyjoint JOINT_NAME BODY1_NAME BODY2_NAME ground_anchor_x ground_anchor_y anchor1_x anchor1_y anchor2_x anchor2_y ratio
	if(ac == 9) {
			currentObjectType = e_b2PulleyJointType;		

			error("pulley joint is not finished yet");
			reset();
			return;

	
	} else {
		error("begin pulleyjoint JOINT_NAME BODY1_NAME BODY2_NAME ground_anchor_x ground_anchor_y anchor1_x anchor1_y anchor2_x anchor2_y ratio");
		reset();
		return;
	}
}

void b2ObjectFactory::beginGearJoint(long ac, t_atom * av) {
//begin gearjoint JOINT_NAME JOINT_1_NAME JOINT_2_NAME ratio
	if(ac == 3) {
		currentObjectType = e_b2GearJointType;		
			error("gear joint is not finished yet");
			reset();
			return;

	
	} else {
		error("begin gearjoint JOINT_NAME JOINT_1_NAME JOINT_2_NAME ratio");
		reset();
		return;
	}
}

/* there are two ways to make a mousejoint ... one is more automated!! */

void b2ObjectFactory::beginMouseJoint(long ac, t_atom * av) {
//begin mousejoint JOINT_NAME BODY1_NAME target_x target_y maxForce	
	
	currentObjectType = e_b2MouseJointType;
	
	
//	printf("XXXXXXXXXXXX creating MOUSE JOINT!!\n\n\n");



	if(ac == 1) {

			

		
			char* body1Name =  (atom_getsym(av))->s_name;
		
			if(userDataManager->has(body1Name)) {
				body1 = userDataManager->getBody(body1Name);
				parentBody1 = body1Name;
			} else {
				error("no such parent body \"%s\" exists.",body1Name);
				reset();
				return;
			}


//			long targetX = P2M(atom_getlong(av+1));
//			long targetY = P2M(atom_getlong(av+2));
			float maxForceRatio = 1;//atom_getfloat(av+3);

//			pos
			

			mouseJointDef.body1 = world->GetGroundBody();
			mouseJointDef.body2 = body1;
			mouseJointDef.target = body1->GetWorldCenter();//b2Vec2(targetX,targetY);
			//mouseJointDef.maxForce = maxForce;			
			
			mouseJointDef.maxForce =  maxForceRatio * 1000.0f * body1->GetMass();



	} else 
	
	if( ac == 2) {
	// begin mousejoint JOINT_NAME target_x target_y
 	
	
			long x = atom_getlong(av);
			long y = atom_getlong(av+1);
			
	//		printf("XXXXXXXXXXXXXXXXXX %ld %ld\n", x , y);
			
/*
			
			if(x == 0 && y == 0) {
				error("x and y are 0");
				reset();
				return;
			}

*/
			b2Vec2 p = b2Vec2(P2M(x),P2M(y));
			
			// Make a small box.
			b2AABB aabb;
			b2Vec2 d;
			d.Set(0.001f, 0.001f);
			aabb.lowerBound = p - d;
			aabb.upperBound = p + d;

			// Query the world for overlapping shapes.
			const int32 k_maxCount = 10;
			b2Shape* shapes[k_maxCount];
			int32 count = world->Query(aabb, shapes, k_maxCount);
			
			post("%ld count",count);
			
			
			b2Body* body = NULL;
			for (int32 i = 0; i < count; ++i)
			{
				b2Body* shapeBody = shapes[i]->GetBody();
				if (shapeBody->IsStatic() == false && shapeBody->GetMass() > 0.0f)
				{
					bool inside = shapes[i]->TestPoint(shapeBody->GetXForm(), p);
					if (inside)
					{
						body = shapes[i]->GetBody();
						break;
					}
				}
			}
			
		
			if (body)
			{
				b2UserData* ud = (b2UserData*)body->GetUserData();
				if(ud != NULL) {
				
						mouseJointDef.body1 = world->GetGroundBody();
						mouseJointDef.body2 = body;
						body1 = world->GetGroundBody(); // for later
						body2 = body;
						mouseJointDef.target = p;
				#ifdef TARGET_FLOAT32_IS_FIXED
						mouseJointDef.maxForce = (body->GetMass() < 16.0)? 
							(1000.0f * body->GetMass()) : float32(16000.0);
				#else
						mouseJointDef.maxForce = 1000.0f * body->GetMass();
				#endif
					} else {
						error("no body at location (%ld,%ld)",atom_getlong(av),atom_getlong(av+1));
						reset();
						return;
					}

					
					
				} else {
					error("body had no name or NO BODY");
					reset();
					return;
				}
				
		
	} else {
		error("begin mousejoint JOINT_NAME target_x target_y OR begin mousejoint JOINT_NAME BODY1_NAME target_x target_y maxForceRatio");
		reset();
		return;
	}

}

void b2ObjectFactory::endBody() {
	/* put a body in play! */
	b2Body* body = world->CreateBody(&bodyDef);
	b2UserData* ud = new b2UserData(objectName, currentObjectType, body);

	/* set user data if needed */
	if(userDataCount > 0) {
		for(int i = 0; i < userDataCount; i++) {
			ud->ac++;
			ud->av[i] = userDataValue[i];
		}
	}
	
	userDataManager->add(objectName,ud);

}
void b2ObjectFactory::endCircle() {
	/* put a shape in play! */
	b2CircleShape* ss = (b2CircleShape*)body1->CreateShape(&circleShapeDef);
	body1->SetMassFromShapes();
	body1->WakeUp();
	b2UserData* ud = new b2UserData(objectName, currentObjectType, ss);

	/* set user data if needed */
	if(userDataCount > 0) {
		for(int i = 0; i < userDataCount; i++) {
			ud->ac++;
			ud->av[i] = userDataValue[i];
		}
	}
	
	userDataManager->add(objectName,ud);
}
void b2ObjectFactory::endPolygon() {
	/* put a shape in play! */
	
	if(vertices.size() < 3) {
		error("polygons need at least 3 vertices, resetting"); 
		reset();
		return;
	}
	
	
	
	
	
/*88888888888*/	

	/* OLD CHECKING STUFF 

	b2Vec2 m_normals[polyShapeDef.vertexCount];

	// Compute normals. Ensure the edges have non-zero length.
	for (int32 i = 0; i < polyShapeDef.vertexCount; ++i)
	{
	
//		post("vertex = %f, %f",polyShapeDef.vertices[i].x,polyShapeDef.vertices[i].y);

	
	
		int32 i1 = i;
		int32 i2 = i + 1 < polyShapeDef.vertexCount ? i + 1 : 0;
		b2Vec2 edge = polyShapeDef.vertices[i2] - polyShapeDef.vertices[i1];
		
		if(edge.LengthSquared() <= B2_FLT_EPSILON * B2_FLT_EPSILON) {
			error("Your poly has zero (or near-zero) length edges.");
			reset();
			return;
		}
		
		m_normals[i] = b2Cross(edge, 1.0f);
		m_normals[i].Normalize();
	}

	// Ensure the polygon is convex.
	for (int32 i = 0; i < polyShapeDef.vertexCount; ++i)
	{
		for (int32 j = 0; j < polyShapeDef.vertexCount; ++j)
		{
			// Don't check vertices on the current edge.
			if (j == i || j == (i + 1) % polyShapeDef.vertexCount)
			{
				continue;
			}
			
			// Your polygon is non-convex (it has an indentation).
			// Or your polygon is too skinny.
			float32 s = b2Dot(m_normals[i], polyShapeDef.vertices[j] - polyShapeDef.vertices[i]);
			//b2Assert(s < -b2_linearSlop);
			
			if(s >= -b2_linearSlop) {
				error("Your polygon is non-convex (it has an indentation) or your polygon is too skinny or it isn't winding in the right direction.");
				reset();
				return;
			}
		}
	}

	// Ensure the polygon is counter-clockwise.
	for (int32 i = 1; i < polyShapeDef.vertexCount; ++i)
	{
		float32 cross = b2Cross(m_normals[i-1], m_normals[i]);

		// Keep asinf happy.
		cross = b2Clamp(cross, -1.0f, 1.0f);

		// You have consecutive edges that are almost parallel on your polygon.
		float32 angle = asinf(cross);
		//b2Assert(angle > b2_angularSlop);
		
			if(angle <= b2_angularSlop) {
				error("You have consecutive edges that are almost parallel on your polygon.");
				reset();
				return;
			}		
				
					
	}
	
	*/
	
	
	
	// the vertices are now here!!
	b2Vec2 verts[vertices.size()];

	for(int i = 0; i < vertices.size(); i++) {
		verts[i] = vertices[i];
	}
	
	b2Polygon polygon(verts, vertices.size());
	
	std::vector<b2PolygonShape*> newPolys;

	DecomposeConvexAndAddTo_MAX(&polygon, body1, &polyShapeDef, newPolys);
	
	

	
	
///	DecomposeConvexAndAddTo

	
	/* SKIPPING THE DAMNABLE USERDATA FOR NOW >>.. */
	

/*88888888888*/	
	
//	b2PolygonShape* ss = (b2PolygonShape*)body1->CreateShape(&polyShapeDef);
	body1->SetMassFromShapes();
	body1->WakeUp();


	b2UserData* ud = new b2UserData(objectName, currentObjectType, &newPolys);

	// set user data if needed 
	if(userDataCount > 0) {
		for(int i = 0; i < userDataCount; i++) {
			ud->ac++;
			ud->av[i] = userDataValue[i];
		}
	}
	
	userDataManager->add(objectName,ud); 

	
	
}
void b2ObjectFactory::endRevoluteJoint() {
	b2RevoluteJoint* ss = (b2RevoluteJoint*)world->CreateJoint(&revoluteJointDef);
	b2UserData* ud = new b2UserData(objectName, currentObjectType, ss);

	/* set user data if needed */
	if(userDataCount > 0) {
		for(int i = 0; i < userDataCount; i++) {
			ud->ac++;
			ud->av[i] = userDataValue[i];
		}
	}
	
	userDataManager->add(objectName,ud);

}

/* TO DO ALL OF THESE FINISHES!!! */

void b2ObjectFactory::endDistanceJoint() {

	b2DistanceJoint* ss = (b2DistanceJoint*)world->CreateJoint(&distanceJointDef);
	b2UserData* ud = new b2UserData(objectName, currentObjectType, ss);

	/* set user data if needed */
	if(userDataCount > 0) {
		for(int i = 0; i < userDataCount; i++) {
			ud->ac++;
			ud->av[i] = userDataValue[i];
		}
	}
	
	userDataManager->add(objectName,ud);

}
void b2ObjectFactory::endPrismaticJoint() {
	b2PrismaticJoint* ss = (b2PrismaticJoint*)world->CreateJoint(&prismaticJointDef);
	b2UserData* ud = new b2UserData(objectName, currentObjectType, ss);

	/* set user data if needed */
	if(userDataCount > 0) {
		for(int i = 0; i < userDataCount; i++) {
			ud->ac++;
			ud->av[i] = userDataValue[i];
		}
	}
	
	userDataManager->add(objectName,ud);
}
void b2ObjectFactory::endPullyJoint() {
	b2PulleyJoint* ss = (b2PulleyJoint*)world->CreateJoint(&pulleyJointDef);
	b2UserData* ud = new b2UserData(objectName, currentObjectType, ss);

	/* set user data if needed */
	if(userDataCount > 0) {
		for(int i = 0; i < userDataCount; i++) {
			ud->ac++;
			ud->av[i] = userDataValue[i];
		}
	}
	
	userDataManager->add(objectName,ud);


}
void b2ObjectFactory::endGearJoint() {
	b2GearJoint* ss = (b2GearJoint*)world->CreateJoint(&gearJointDef);
	b2UserData* ud = new b2UserData(objectName, currentObjectType, ss);

	/* set user data if needed */
	if(userDataCount > 0) {
		for(int i = 0; i < userDataCount; i++) {
			ud->ac++;
			ud->av[i] = userDataValue[i];
		}
	}
	
	userDataManager->add(objectName,ud);


}
void b2ObjectFactory::endMouseJoint() {

	b2MouseJoint* ss = (b2MouseJoint*)world->CreateJoint(&mouseJointDef);
	body1->WakeUp();
	b2UserData* ud = new b2UserData(objectName, currentObjectType, ss);

	/* set user data if needed */
	if(userDataCount > 0) {
		for(int i = 0; i < userDataCount; i++) {
			ud->ac++;
			ud->av[i] = userDataValue[i];
		}
	}

	
	userDataManager->add(objectName,ud);
}



 /**
	 * Decomposes a polygon into convex polygons and adds all pieces to a b2BodyDef
     * using a prototype b2PolyDef. All fields of the prototype are used for every
     * shape except the vertices (friction, restitution, density, etc).
     *
     * If you want finer control, you'll have to add everything by hand.
     *
     * This is the simplest method to add a complicated polygon to a body.
	 *
	 * Until Box2D's b2BodyDef behavior changes, this method returns a pointer to
	 * a heap-allocated array of b2PolyDefs, which must be deleted by the user
	 * after the b2BodyDef is added to the world.
     */
void b2ObjectFactory::DecomposeConvexAndAddTo_MAX(b2Polygon* p, b2Body* bd, b2PolygonDef* prototype, 
											std::vector<b2PolygonShape*>& subPolyPointers) { // pass by reference w/o const b/c we want to modify it
		
		static bool B2_POLYGON_REPORT_ERRORS = true;

        if (p->nVertices < 3) return;
		
        b2Polygon* decomposed = new b2Polygon[p->nVertices - 2]; //maximum number of polys
        int32 nPolys = DecomposeConvex(p, decomposed, p->nVertices - 2);
//		printf("npolys: %d",nPolys);
		b2PolygonDef* pdarray = new b2PolygonDef[2*p->nVertices];//extra space in case of splits
		int32 extra = 0;
        for (int32 i = 0; i < nPolys; ++i) {
            b2PolygonDef* toAdd = &pdarray[i+extra];
			 *toAdd = *prototype;
			 //Hmm, shouldn't have to do all this...
			 /*
			 toAdd->type = prototype->type;
			 toAdd->friction = prototype->friction;
			 toAdd->restitution = prototype->restitution;
			 toAdd->density = prototype->density;
			 toAdd->userData = prototype->userData;
			 toAdd->categoryBits = prototype->categoryBits;
			 toAdd->maskBits = prototype->maskBits;
			 toAdd->groupIndex = prototype->groupIndex;//*/
			 //decomposed[i].print();
			b2Polygon curr = decomposed[i];
			//TODO ewjordan: move this triangle handling to a better place so that
			//it happens even if this convenience function is not called.
			if (curr.nVertices == 3){
					//Check here for near-parallel edges, since we can't
					//handle this in merge routine
					for (int j=0; j<3; ++j){
						int32 lower = (j == 0) ? (curr.nVertices - 1) : (j - 1);
						int32 middle = j;
						int32 upper = (j == curr.nVertices - 1) ? (0) : (j + 1);
						float32 dx0 = curr.x[middle] - curr.x[lower]; float32 dy0 = curr.y[middle] - curr.y[lower];
						float32 dx1 = curr.x[upper] - curr.x[middle]; float32 dy1 = curr.y[upper] - curr.y[middle];
						float32 norm0 = sqrtf(dx0*dx0+dy0*dy0);	float32 norm1 = sqrtf(dx1*dx1+dy1*dy1);
						
						if ( !(norm0 > 0.0f && norm1 > 0.0f) ) {
							//Identical points, don't do anything!
							goto Skip;
						}
						
						dx0 /= norm0; dy0 /= norm0;
						dx1 /= norm1; dy1 /= norm1;
						
						float32 cross = dx0 * dy1 - dx1 * dy0;
						float32 dot = dx0*dx1 + dy0*dy1;
						
						if (fabs(cross) < b2_angularSlop && dot > 0) {
							//Angle too close, split the triangle across from this point.
							//This is guaranteed to result in two triangles that satify
							//the tolerance (one of the angles is 90 degrees)
							float32 dx2 = curr.x[lower] - curr.x[upper]; float32 dy2 = curr.y[lower] - curr.y[upper];
							float32 norm2 = sqrtf(dx2*dx2+dy2*dy2);
							if (norm2 == 0.0f) {
								goto Skip;
							}
							dx2 /= norm2; dy2 /= norm2;
							float32 thisArea = curr.GetArea();
							float32 thisHeight = 2.0f * thisArea / norm2;
							float32 buffer2 = dx2;
							dx2 = dy2; dy2 = -buffer2;
							//Make two new polygons
							//printf("dx2: %f, dy2: %f, thisHeight: %f, middle: %d\n",dx2,dy2,thisHeight,middle);
							float32 newX1[3] = { curr.x[middle]+dx2*thisHeight, curr.x[lower], curr.x[middle] };
							float32 newY1[3] = { curr.y[middle]+dy2*thisHeight, curr.y[lower], curr.y[middle] };
							float32 newX2[3] = { newX1[0], curr.x[middle], curr.x[upper] };
							float32 newY2[3] = { newY1[0], curr.y[middle], curr.y[upper] };
							b2Polygon p1(newX1,newY1,3);
							b2Polygon p2(newX2,newY2,3);
							if (p1.IsUsable()){
								p1.AddTo(*toAdd);
								b2Shape* p = bd->CreateShape(toAdd);
								subPolyPointers.push_back((b2PolygonShape*)p); /* add to an array for housekeeping! */						
								++extra;
							} else if (B2_POLYGON_REPORT_ERRORS){
								printf("Didn't add unusable polygon.  Dumping vertices:\n");
								p1.print();
							}
							if (p2.IsUsable()){
								p2.AddTo(pdarray[i+extra]);
								b2Shape* p = bd->CreateShape(&pdarray[i+extra]);
								subPolyPointers.push_back((b2PolygonShape*)p); /* add to an array for housekeeping! */
							} else if (B2_POLYGON_REPORT_ERRORS){
								printf("Didn't add unusable polygon.  Dumping vertices:\n");
								p2.print();
							}
							goto Skip;
						}
					}

			}
			if (decomposed[i].IsUsable()){
				decomposed[i].AddTo(*toAdd);
				b2Shape* p = bd->CreateShape(toAdd);
				subPolyPointers.push_back((b2PolygonShape*)p); /* add to an array for housekeeping! */
			
			} else if (B2_POLYGON_REPORT_ERRORS){
				printf("Didn't add unusable polygon.  Dumping vertices:\n");
				decomposed[i].print();
			}
Skip:
			;
        }
		delete[] pdarray;
        delete[] decomposed;
		return;// pdarray; //needs to be deleted after body is created
}

